package game.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import common.model.po.GRecipe;
import common.model.po.GRecipeBuilding;
import common.model.po.GRecipeItem;
import common.model.request.base.PaginationRequest;
import common.model.response.base.Result;
import common.service.CommonGRecipeBuildingService;
import common.service.CommonGRecipeItemService;
import common.util.BigFractionUtil;
import common.util.PageHandler;
import game.mapper.GRecipeMapper;
import game.model.request.SaveRecipeRequest;
import game.model.request.SearchRecipeRequest;
import game.model.vo.SearchRecipeVo;
import game.service.GRecipeService;
import org.apache.commons.math3.fraction.BigFraction;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 配方和原料的多对多关系服务实现类
 *
 * @author 米泽鹏
 * @since 2022-02-26
 */
@Service
public class GRecipeServiceImpl extends ServiceImpl<GRecipeMapper, GRecipe> implements GRecipeService {

	@Resource
	private GRecipeMapper mapper;
	@Resource
	private CommonGRecipeItemService recipeItemService;
	@Resource
	private CommonGRecipeBuildingService recipeBuildingService;

	@Override
	public Page<SearchRecipeVo> pageRecipe(PaginationRequest<SearchRecipeRequest, GRecipe> paginationRequest) {
		SearchRecipeRequest request = paginationRequest.getParams();
		// 查询所有可以生产该物品的配方搭配（区分产物是物品还是建筑）
		Page<SearchRecipeVo> page = mapper.searchRecipe(PageHandler.createEmptyPage(paginationRequest.buildPage()), request);
		if (page.getTotal() == 0) {
			return page;
		}
		for (SearchRecipeVo searchRecipeVo : page.getRecords()) {
			// 显示的配方名称
			if (request.getProductItemId() == null && request.getProductBuildingId() == null) {
				searchRecipeVo.setRecipeNameDisplayed(searchRecipeVo.getRecipeName());
			} else {
				long index = (page.getCurrent() - 1) * page.getSize() + page.getRecords().indexOf(searchRecipeVo);
				searchRecipeVo.setRecipeNameDisplayed(searchRecipeVo.getRecipeName() + "（" + (index == 0 ? "标准配方" : "替代配方" + index) + "）");
			}
		}
		return page;
	}

	@Override
	public SearchRecipeVo getRecipeDetailById(Long recipeId) {
		return mapper.getRecipeDetailById(recipeId);
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public Result<?> saveRecipe(SaveRecipeRequest request) {
		// 区分产物类型：1-物品，2-建筑
		Integer productType = request.getProductType();
		// 产物是物品
		if (productType == 1) {
			SaveRecipeRequest.Product productSample = request.getProductList().stream().filter(item -> item.getQuantityPerMinute() != null).collect(Collectors.toList()).get(0);
			// 分钟数量和每次数量的比值
			BigFraction ratio = BigFractionUtil.valueOf(productSample.getQuantityPerMinute(), productSample.getQuantityPerProduction());
			// 填充原料的分钟数量
			for (SaveRecipeRequest.Material material : request.getMaterialList()) {
				material.setQuantityPerMinute(ratio.multiply(BigFractionUtil.valueOf(material.getQuantityPerProduction())).bigDecimalValue(5, BigDecimal.ROUND_HALF_UP));
			}
			// 填充产物的分钟数量
			for (SaveRecipeRequest.Product product : request.getProductList()) {
				if (product.getQuantityPerMinute() == null) {
					product.setQuantityPerMinute(ratio.multiply(BigFractionUtil.valueOf(product.getQuantityPerProduction())).bigDecimalValue(5, BigDecimal.ROUND_HALF_UP));
				}
			}
			// 配方
			GRecipe recipe = new GRecipe();
			recipe.setId(request.getRecipeId());
			recipe.setRecipeName(request.getRecipeName());
			recipe.setSort(request.getSort());
			saveOrUpdate(recipe);
			// 如果是更新，先删除原有的关联关系
			if (request.getRecipeId() != null) {
				recipeBuildingService.remove(new LambdaQueryWrapper<GRecipeBuilding>().eq(GRecipeBuilding::getRecipeId, request.getRecipeId()));
				recipeItemService.remove(new LambdaQueryWrapper<GRecipeItem>().eq(GRecipeItem::getRecipeId, request.getRecipeId()));
			}
			// 配方和建筑的关联关系
			List<GRecipeBuilding> recipeBuildingList = Lists.newArrayList();
			List<SaveRecipeRequest.Building> buildingList = request.getBuildingList();
			for (SaveRecipeRequest.Building building : buildingList) {
				GRecipeBuilding gRecipeBuilding = new GRecipeBuilding();
				gRecipeBuilding.setRecipeId(recipe.getId());
				gRecipeBuilding.setBuildingId(building.getBuilding().getId());
				gRecipeBuilding.setBuildingName(building.getBuilding().getBuildingName());
				recipeBuildingList.add(gRecipeBuilding);
			}
			recipeBuildingService.saveBatch(recipeBuildingList);
			// 配方和原料、产物的关联关系
			List<GRecipeItem> recipeItemList = Lists.newArrayList();
			// 原料
			for (SaveRecipeRequest.Material material : request.getMaterialList()) {
				GRecipeItem gRecipeItem = new GRecipeItem();
				gRecipeItem.setProductType(productType);
				gRecipeItem.setRecipeId(recipe.getId());
				gRecipeItem.setType(0);
				gRecipeItem.setItemId(material.getItem().getId());
				gRecipeItem.setItemName(material.getItem().getItemName());
				gRecipeItem.setQuantityPerProduction(material.getQuantityPerProduction());
				gRecipeItem.setQuantityPerMinute(material.getQuantityPerMinute());
				recipeItemList.add(gRecipeItem);
			}
			// 产物
			for (SaveRecipeRequest.Product product : request.getProductList()) {
				GRecipeItem gRecipeItem = new GRecipeItem();
				gRecipeItem.setProductType(productType);
				gRecipeItem.setRecipeId(recipe.getId());
				gRecipeItem.setType(1);
				gRecipeItem.setItemId(product.getItem().getId());
				gRecipeItem.setItemName(product.getItem().getItemName());
				gRecipeItem.setQuantityPerProduction(product.getQuantityPerProduction());
				gRecipeItem.setQuantityPerMinute(product.getQuantityPerMinute());
				recipeItemList.add(gRecipeItem);
			}
			recipeItemService.saveBatch(recipeItemList);
		} else {// 产物是建筑
			// 配方
			GRecipe recipe = new GRecipe();
			recipe.setId(request.getRecipeId());
			recipe.setRecipeName(request.getRecipeName());
			recipe.setSort(request.getSort());
			saveOrUpdate(recipe);
			// 如果是更新，先删除原有的关联关系
			if (request.getRecipeId() != null) {
				recipeItemService.remove(new LambdaQueryWrapper<GRecipeItem>().eq(GRecipeItem::getRecipeId, request.getRecipeId()));
			}
			// 配方和原料、产物的关联关系
			List<GRecipeItem> recipeItemList = Lists.newArrayList();
			// 原料
			for (SaveRecipeRequest.Material material : request.getMaterialList()) {
				GRecipeItem gRecipeItem = new GRecipeItem();
				gRecipeItem.setProductType(productType);
				gRecipeItem.setRecipeId(recipe.getId());
				gRecipeItem.setType(0);
				gRecipeItem.setItemId(material.getItem().getId());
				gRecipeItem.setItemName(material.getItem().getItemName());
				gRecipeItem.setQuantityPerProduction(material.getQuantityPerProduction());
				recipeItemList.add(gRecipeItem);
			}
			// 产物
			SaveRecipeRequest.BuildingProduct buildingProduct = request.getBuildingProduct();
			GRecipeItem gRecipeItem = new GRecipeItem();
			gRecipeItem.setProductType(productType);
			gRecipeItem.setRecipeId(recipe.getId());
			gRecipeItem.setType(1);
			gRecipeItem.setItemId(buildingProduct.getId());
			gRecipeItem.setItemName(buildingProduct.getBuildingName());
			gRecipeItem.setQuantityPerProduction(BigDecimal.ONE);
			recipeItemList.add(gRecipeItem);
			recipeItemService.saveBatch(recipeItemList);
		}
		return Result.success();
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public Result<?> deleteRecipe(Long id) {
		// 删除配方
		removeById(id);
		// 配方和建筑的关联关系
		recipeBuildingService.remove(new LambdaQueryWrapper<GRecipeBuilding>().eq(GRecipeBuilding::getRecipeId, id));
		// 配方和物品的关联关系
		recipeItemService.remove(new LambdaQueryWrapper<GRecipeItem>().eq(GRecipeItem::getRecipeId, id));
		return Result.success();
	}

}
